﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Urs.Admin.Infrastructure;
using Urs.Admin.Models.Stores;
using Urs.Core;
using Urs.Core.Caching;
using Urs.Data.Domain.Stores;
using Urs.Data.Domain.Configuration;
using Urs.Services.Stores;
using Urs.Services.Common;
using Urs.Services.Configuration;
using Urs.Services.Users;
using Urs.Services.Directory;
using Urs.Services.ExportImport;
using Urs.Services.Localization;
using Urs.Services.Logging;
using Urs.Services.Media;
using Urs.Services.Orders;
using Urs.Services.Security;
using Urs.Framework.Controllers;
using Urs.Framework.Extensions;
using Urs.Framework.Kendoui;
using Urs.Framework.Mvc;
using Urs.Admin.Models.Common;

namespace Urs.Admin.Controllers
{
    [AdminAuthorize]
    public partial class GoodsController : BaseAdminController
    {
        #region Fields

        private readonly IGoodsService _goodsService;
        private readonly ICategoryService _categoryService;
        private readonly IBrandService _brandService;
        private readonly IUserService _userService;
        private readonly IWorkContext _workContext;
        private readonly IGoodsSpecFormatter _goodsSpecFormatter;
        private readonly IShoppingCartService _shoppingCartService;
        private readonly IGoodsSpecParser _goodsSpecParser;
        private readonly ILocalizationService _localizationService;
        private readonly IGoodsParameterService _goodsParameterService;
        private readonly IPictureService _pictureService;
        private readonly IGoodsTagService _goodsTagService;
        private readonly ICopyGoodsService _copyGoodsService;
        private readonly IPdfService _pdfService;
        private readonly ISettingService _settingService;
        private readonly IExportManager _exportManager;
        private readonly IImportManager _importManager;
        private readonly IActivityLogService _activityLogService;
        private readonly IPermissionService _permissionService;
        private readonly IGoodsSpecService _goodsSpecService;
        private readonly IMeasureService _measureService;
        private readonly MeasureSettings _measureSettings;
        private readonly PdfSettings _pdfSettings;
        private readonly AdminAreaSettings _adminAreaSettings;
        private readonly ICacheManager _cacheManager;

        #endregion

        #region Constructors

        public GoodsController(IGoodsService goodsService,
            ICategoryService categoryService, IBrandService brandService,
            IUserService userService, IWorkContext workContext,
            IGoodsSpecFormatter goodsSpecFormatter, IShoppingCartService shoppingCartService,
            IGoodsSpecParser goodsSpecParser,
            ILocalizationService localizationService,
            IGoodsParameterService goodsParameterService, IPictureService pictureService,
            IGoodsTagService goodsTagService,
            ICopyGoodsService copyGoodsService, IPdfService pdfService,
            ISettingService settingService,
            IExportManager exportManager, IImportManager importManager,
            IActivityLogService activityLogService,
            IPermissionService permissionService,
            IGoodsSpecService goodsSpecService,
            IMeasureService measureService, MeasureSettings measureSettings,
            PdfSettings pdfSettings, AdminAreaSettings adminAreaSettings,
            ICacheManager cacheManager)
        {
            this._goodsService = goodsService;
            this._categoryService = categoryService;
            this._brandService = brandService;
            this._userService = userService;
            this._workContext = workContext;
            this._goodsSpecFormatter = goodsSpecFormatter;
            this._shoppingCartService = shoppingCartService;
            this._goodsSpecParser = goodsSpecParser;
            this._localizationService = localizationService;
            this._goodsParameterService = goodsParameterService;
            this._pictureService = pictureService;
            this._goodsTagService = goodsTagService;
            this._copyGoodsService = copyGoodsService;
            this._pdfService = pdfService;
            this._settingService = settingService;
            this._exportManager = exportManager;
            this._importManager = importManager;
            this._activityLogService = activityLogService;
            this._permissionService = permissionService;
            this._goodsSpecService = goodsSpecService;
            this._measureService = measureService;
            this._measureSettings = measureSettings;
            this._pdfSettings = pdfSettings;
            this._adminAreaSettings = adminAreaSettings;
            this._cacheManager = cacheManager;
        }

        #endregion

        #region Utitilies

        [NonAction]
        protected void UpdateGoodsTagTotals(Goods goods)
        {
            var goodsTags = goods.GoodsTags;
            foreach (var goodsTag in goodsTags)
                _goodsTagService.UpdateGoodsTagTotals(goodsTag.GoodsTag);
        }

        [NonAction]
        private void PrepareCategoryMapping(GoodsModel model, Goods goods)
        {
            if (model == null)
                throw new ArgumentNullException("model");

            var allCategories = SelectListHelper.GetCategoryList(_categoryService, _cacheManager, true);
            if (goods != null)
            {
                var categories = _categoryService.GetCategoriesByGoodsId(goods.Id);
                var catIds = categories.Select(q => q.Id).ToList();
                if (goods.CategoryId > 0) catIds.Add(goods.CategoryId);
                model.CategoryIds = catIds;
            }
            foreach (var c in allCategories)
            {
                if (goods != null)
                {
                    c.Selected = model.CategoryIds.Contains(int.Parse(c.Value));
                    model.AvailableCategories.Add(c);
                }
            }
        }
        [NonAction]
        protected virtual void PrepareBrandMapping(GoodsModel model, Goods goods)
        {
            if (model == null)
                throw new ArgumentNullException("model");
            model.AvailableBrands.Add(new SelectListItem()
            {
                Text = "--请选择--",
                Value = "0"
            });
            foreach (var brand in _brandService.GetAll(showHidden: true))
            {
                model.AvailableBrands.Add(new SelectListItem
                {
                    Text = brand.Name,
                    Value = brand.Id.ToString(),
                    Selected = goods != null ? goods.BrandId == brand.Id : false
                });
            }
        }

        [NonAction]
        private void PrepareGoodsPictureThumbnailModel(GoodsModel model, Goods goods)
        {
            if (model == null)
                throw new ArgumentNullException("model");

            if (goods != null)
            {
                var defaultGoodsPicture = _pictureService.GetPicturesByGoodsId(goods.Id, 1).FirstOrDefault();
                model.PictureThumbnailUrl = _pictureService.GetPictureUrl(defaultGoodsPicture, 75, true);
            }
        }
        [NonAction]
        private void PrepareGoodsPictureModel(GoodsModel model, Goods goods)
        {
            var list = new List<PreparePic>();
            if (goods != null)
            {
                var pp = _goodsService.GetGoodsPicturesByGoodsId(goods.Id);
                list = pp.OrderByDescending(q => q.DisplayOrder).Select(p =>
                 {
                     var img = new PreparePic { pictureId = p.PictureId, imageUrl = _pictureService.GetPictureUrl(p.PictureId, 100) };
                     return img;
                 }).ToList();
            }
            model.imgs = Newtonsoft.Json.JsonConvert.SerializeObject(list);
        }
        [NonAction]
        private void SaveGoodsPicture(Goods goods, IList<int> pictureIds)
        {
            var existingPictures = goods == null ? new List<GoodsPicture>() : _goodsService.GetGoodsPicturesByGoodsId(goods.Id);
            var goodsPictureToRemove = new List<GoodsPicture>();
            foreach (var existingPicture in existingPictures)
            {
                bool found = false;
                foreach (int pictureId in pictureIds)
                {
                    if (existingPicture.PictureId == pictureId)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    goodsPictureToRemove.Add(existingPicture);
                }
            }
            foreach (var goodsPicture in goodsPictureToRemove)
            {
                _goodsService.DeleteGoodsPicture(goodsPicture);
            }
            foreach (int pictureId in pictureIds)
            {
                var picture = existingPictures.FirstOrDefault(q => q.PictureId == pictureId);
                if (picture == null)
                {
                    //add new goods tag
                    var pp = new GoodsPicture()
                    {
                        PictureId = pictureId,
                        GoodsId = goods.Id,
                        DisplayOrder = pictureIds.Count - pictureIds.IndexOf(pictureId)
                    };
                    _goodsService.InsertGoodsPicture(pp);
                }
                else
                {
                    picture.DisplayOrder = pictureIds.Count - pictureIds.IndexOf(pictureId);
                    _goodsService.UpdateGoodsPicture(picture);
                }
            }
        }
        [NonAction]
        private void PrepareGoodsSpecModel(GoodsModel model, Goods goods)
        {
            var list = new List<PrepareSpec>();
            if (goods != null)
            {
                var pp = _goodsParameterService.GetGoodsParameterMappingByGoodsId(goods.Id);
                list = pp.Select(p =>
                {
                    var option = p.GoodsParameterOption;
                    var spec = p.GoodsParameterOption.Mapping;
                    var ps = new PrepareSpec { id = spec.Id, name = spec.Name, valid = option.Id, valname = option.Name };
                    return ps;
                }).ToList();
            }
            model.canshu = Newtonsoft.Json.JsonConvert.SerializeObject(list);
        }
        [NonAction]
        private void SaveGoodsSpec(Goods goods, IList<int> specIds)
        {
            var existingSpecs = _goodsParameterService.GetGoodsParameterMappingByGoodsId(goods.Id);
            var goodsSpecsToRemove = new List<GoodsParameterMapping>();
            foreach (var existingSpec in existingSpecs)
            {
                bool found = false;
                foreach (int specId in specIds)
                {
                    if (existingSpec.GoodsParameterOptionId == specId)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    goodsSpecsToRemove.Add(existingSpec);
                }
            }
            foreach (var item in goodsSpecsToRemove)
            {
                _goodsParameterService.DeleteGoodsParameterMapping(item);
            }
            foreach (int specId in specIds)
            {
                var spec = existingSpecs.FirstOrDefault(q => q.GoodsParameterOptionId == specId);
                if (spec == null)
                {
                    //add new goods tag
                    var pp = new GoodsParameterMapping()
                    {
                        GoodsParameterOptionId = specId,
                        GoodsId = goods.Id,
                        AllowFiltering = true
                    };
                    _goodsParameterService.InsertGoodsParameterMapping(pp);
                }
            }
        }
        [NonAction]
        private void PrepareGoodsAttrModel(GoodsModel model, Goods goods)
        {
            var list = new List<PrepareAttr>();
            if (goods != null)
            {
                var pp = _goodsSpecService.GetGoodsSpecMappingByGoodsId(goods.Id);
                foreach (var p in pp)
                {
                    var attr = list.FirstOrDefault(q => q.value == p.GoodsSpecId);
                    if (attr == null)
                    {
                        attr = new PrepareAttr() { value = p.GoodsSpecId, name = p.GoodsSpecName };
                        list.Add(attr);

                    }

                    var attrValue = _goodsSpecService.GetGoodsSpecValueById(p.GoodsSpecValueId);
                    if (attr.attrValArr.FirstOrDefault(ava => ava.value == attrValue.Id) == null && attrValue != null)
                        attr.attrValArr.Add(new PrepareAttr.GoodsAttrValue() { value = attrValue.Id, name = attrValue.Name });
                }
            }
            model.attr = Newtonsoft.Json.JsonConvert.SerializeObject(list);
        }
        [NonAction]
        private void SaveGoodsAttr(Goods goods, List<PrepareAttr> attrs)
        {
            var existingAttrs = _goodsSpecService.GetGoodsSpecMappingByGoodsId(goods.Id);
            var goodsAttrMapToRemove = new List<GoodsSpecMapping>();

            List<PrepareAttr.GoodsAttrValue> attrValues = new List<PrepareAttr.GoodsAttrValue>();
            foreach (var item in attrs)
                attrValues.AddRange(item.attrValArr);

            foreach (var existingAttr in existingAttrs)
            {
                bool found = false;
                foreach (var value in attrValues)
                {
                    if (existingAttr.GoodsSpecValueId == value.value)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    goodsAttrMapToRemove.Add(existingAttr);
                }
            }
            foreach (var item in goodsAttrMapToRemove)
            {
                _goodsSpecService.DeleteGoodsSpecMapping(item);
            }
            foreach (PrepareAttr attr in attrs)
            {
                foreach (var value in attr.attrValArr)
                {
                    var val = existingAttrs.FirstOrDefault(q => q.GoodsSpecValueId == value.value);
                    if (val == null)
                    {
                        //add new goods tag
                        var pp = new GoodsSpecMapping()
                        {
                            GoodsId = goods.Id,
                            GoodsSpecId = attr.value,
                            GoodsSpecName=attr.name,
                            GoodsSpecValueId = value.value
                        };
                        _goodsSpecService.InsertGoodsSpecMapping(pp);
                    }
                }
            }
        }
        [NonAction]
        private void PrepareAttrTableModel(GoodsModel model, Goods goods)
        {
            var list = new List<AttrTable>();
            if (goods != null)
            {
                var combinations = _goodsSpecService.GetAllGoodsSpecCombinations(goods.Id);
                foreach (var item in combinations)
                {
                    var at = new AttrTable();
                    at.info.price = item.Price;
                    at.info.qty = item.StockQuantity;
                    at.info.sku = item.Sku;
                    var values = _goodsSpecParser.ParseGoodsSpecValues(item.AttributesXml);
                    foreach (var value in values)
                    {
                        at.arrs.Add(new AttrTable.AttrValueItem()
                        {
                            value = value.Id,
                            name = value.Name

                        });
                    }
                    list.Add(at);
                }
            }
            model.attrtable = Newtonsoft.Json.JsonConvert.SerializeObject(list);
        }
        [NonAction]
        private void SaveAttrTable(Goods goods, List<AttrTable> attrTables)
        {
            var existingCombinations = _goodsSpecService.GetAllGoodsSpecCombinations(goods.Id);
            var goodsAttrCombinationToRemove = new List<GoodsSpecCombination>();

            foreach (var existingCombination in existingCombinations)
            {
                var attrValues = _goodsSpecParser.ParseGoodsSpecValues(existingCombination.AttributesXml);
                var values = attrValues.Select(q => q.Id);

                bool found = false;
                foreach (var table in attrTables)
                {
                    var options = table.arrs.Select(q => q.value);
                    if (Enumerable.SequenceEqual(options, values))
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    goodsAttrCombinationToRemove.Add(existingCombination);
                }
            }
            foreach (var item in goodsAttrCombinationToRemove)
            {
                _goodsSpecService.DeleteGoodsSpecCombination(item);
            }
            foreach (AttrTable attrTable in attrTables)
            {
                var options = attrTable.arrs.Select(q => q.value);
                bool found = false;
                foreach (var combination in existingCombinations)
                {
                    var attrValues = _goodsSpecParser.ParseGoodsSpecValues(combination.AttributesXml);
                    var values = attrValues.Select(q => q.Id);

                    if (Enumerable.SequenceEqual(options, values))
                    {
                        found = true;
                        combination.Price = attrTable.info.price;
                        combination.StockQuantity = attrTable.info.qty;
                        combination.Sku = attrTable.info.sku;
                        _goodsSpecService.UpdateGoodsSpecCombination(combination);
                    }
                }
                if (!found)
                {
                    string selectedAttributes = string.Empty;
                    var goodsSpecs = _goodsSpecService.GetGoodsSpecMappingByGoodsId(goods.Id);
                    foreach (var attribute in goodsSpecs)
                    {
                        if (options.Contains(attribute.GoodsSpecValueId))
                        {
                            int selectedAttributeId = attribute.GoodsSpecValueId;
                            if (selectedAttributeId > 0)
                                selectedAttributes = _goodsSpecParser.AddGoodsSpec(selectedAttributes,
                                    attribute, selectedAttributeId.ToString());
                        }
                    }

                    var pp = new GoodsSpecCombination()
                    {
                        GoodsId = goods.Id,
                        AttributesXml = selectedAttributes,
                        Price = attrTable.info.price,
                        Sku = attrTable.info.sku,
                        StockQuantity = attrTable.info.qty
                    };
                    _goodsSpecService.InsertGoodsSpecCombination(pp);
                }
            }
        }
        private void SaveGoodsCategory(Goods goods, List<int> categoryIds)
        {
            var categories = _categoryService.GetAllCategories();
            var pcategories = new List<GoodsCategory>();
            if (goods != null && goods.Id > 0)
                pcategories = _categoryService.GetGoodsCategoriesByGoodsId(goods.Id).ToList();
            foreach (var category in categories)
            {
                if (categoryIds != null && categoryIds.Contains(category.Id))
                {
                    if (pcategories.Count(mapping => mapping.CategoryId == category.Id) == 0)
                        _categoryService.InsertGoodsCategory(new GoodsCategory() { GoodsId = goods.Id, CategoryId = category.Id });
                }
                else
                {
                    //remove role
                    if (pcategories.Count(mapping => mapping.CategoryId == category.Id) > 0)
                    {
                        _categoryService.DeleteGoodsCategory(pcategories.FirstOrDefault(mapping => mapping.CategoryId == category.Id));
                    }
                }
            }
        }
        [NonAction]
        private void PrepareTags(GoodsModel model, Goods goods)
        {
            if (model == null)
                throw new ArgumentNullException("model");

            if (goods != null)
            {
                var result = new StringBuilder();
                for (int i = 0; i < goods.GoodsTags.Count; i++)
                {
                    var pt = goods.GoodsTags.ToList()[i];
                    result.Append(pt.GoodsTag.Name);
                    if (i != goods.GoodsTags.Count - 1)
                        result.Append(", ");
                }
                model.GoodsTags = result.ToString();
            }
        }
        [NonAction]
        private string[] ParseGoodsTags(string goodsTags)
        {
            var result = new List<string>();
            if (!String.IsNullOrWhiteSpace(goodsTags))
            {
                string[] values = goodsTags.Split(new char[] { ',', ' ', '，', ';', '；', '|', '、' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (string val1 in values)
                    if (!String.IsNullOrEmpty(val1.Trim()))
                        result.Add(val1.Trim());
            }
            return result.ToArray();
        }
        [NonAction]
        private void SaveGoodsTags(Goods goods, string[] goodsTags)
        {
            if (goods == null)
                throw new ArgumentNullException("goods");

            //goods tags
            var existingGoodsTags = goods.GoodsTags.OrderByDescending(pt => pt.GoodsTag.Count).ToList();
            var goodsTagsToRemove = new List<GoodsTag>();
            foreach (var existingGoodsTag in existingGoodsTags)
            {
                bool found = false;
                foreach (string newGoodsTag in goodsTags)
                {
                    if (existingGoodsTag.GoodsTag.Name.Equals(newGoodsTag, StringComparison.InvariantCultureIgnoreCase))
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    goodsTagsToRemove.Add(existingGoodsTag.GoodsTag);
                }
            }
            foreach (var goodsTag in goodsTagsToRemove)
            {
                goods.GoodsTags.Remove(
                    goods.GoodsTags.FirstOrDefault(mapping => mapping.GoodsTagId == goodsTag.Id));
                //ensure goods is saved before updating totals
                _goodsService.UpdateGoods(goods);
                _goodsTagService.UpdateGoodsTagTotals(goodsTag);
            }
            foreach (string goodsTagName in goodsTags)
            {
                GoodsTag goodsTag = null;
                var goodsTag2 = _goodsTagService.GetGoodsTagByName(goodsTagName);
                if (goodsTag2 == null)
                {
                    //add new goods tag
                    goodsTag = new GoodsTag()
                    {
                        Name = goodsTagName,
                        Count = 0
                    };
                    _goodsTagService.InsertGoodsTag(goodsTag);
                }
                else
                {
                    goodsTag = goodsTag2;
                }
                if (!goods.GoodsTagExists(goodsTag.Id))
                {
                    goods.GoodsTags.Add(new GoodsTagMapping { GoodsTag = goodsTag });
                    //ensure goods is saved before updating totals
                    _goodsService.UpdateGoods(goods);
                }
                //update goods tag totals 
                _goodsTagService.UpdateGoodsTagTotals(goodsTag);
            }
        }
        [NonAction]
        protected void PrepareGoodsModel(GoodsModel model, Goods goods, bool setPredefinedValues)
        {
            if (model == null)
                throw new ArgumentNullException("model");
            model.BaseWeightIn = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId).Name;
            model.BaseDimensionIn = _measureService.GetMeasureDimensionById(_measureSettings.BaseDimensionId).Name;

            if (setPredefinedValues)
            {
                model.StockQuantity = 10000;
                model.NotifyAdminForQuantityBelow = 1;
                model.IsShipEnabled = true;
            }
        }
        #endregion

        #region Methods

        #region Goods list / create / edit / delete

        //list 
        public IActionResult Index()
        {
            return RedirectToAction("List");
        }

        public IActionResult List()
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            var model = new GoodsListModel();
            //categories
            model.AvailableCategories.Add(new SelectListItem() { Text = _localizationService.GetResource("Admin.Common.All"), Value = "0" });
            foreach (var c in _categoryService.GetAllCategories(showHidden: true))
                model.AvailableCategories.Add(new SelectListItem() { Text = c.GetCategoryNameWithPrefix(_categoryService), Value = c.Id.ToString() });

            //brands
            model.AvailableBrands.Add(new SelectListItem() { Text = _localizationService.GetResource("Admin.Common.All"), Value = "0" });
            foreach (var m in _brandService.GetAll(true))
                model.AvailableBrands.Add(new SelectListItem() { Text = m.Name, Value = m.Id.ToString() });

            model.PublishedStatus.Add(new SelectListItem() { Text = "--全部--", Value = 0.ToString() });
            model.PublishedStatus.Add(new SelectListItem() { Text = "--已发布--", Value = 1.ToString() });
            model.PublishedStatus.Add(new SelectListItem() { Text = "--未发布--", Value = 2.ToString() });
            return View(model);
        }

        [HttpPost]
        public IActionResult ListJson(PageRequest command, GoodsListModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            var result = new ResponseResult();

            var categoryIds = new List<int>();
            if (model.SearchCategoryId > 0)
                categoryIds.Add(model.SearchCategoryId);
            var list = _goodsService.SearchGoodss(out IList<int> filterableGoodsParameterOptionIds, true,
                categoryIds.ToArray(), brandId: model.SearchBrandId, keywords: model.SearchName,
                orderBy: GoodsSortingEnum.Position, pageIndex: command.Page - 1, pageSize: command.Limit, showHidden: true);

            result.data = list.Select(x =>
            {
                var goodsModel = x.ToModel<GoodsModel>();
                PrepareGoodsPictureThumbnailModel(goodsModel, x);
                return goodsModel;
            });
            result.count = list.TotalCount;
            return Json(result);
        }

        //edit goods
        public IActionResult Edit(int id)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            var goods = _goodsService.GetGoodsById(id);
            if (goods == null || goods.Deleted)
            {
                var model = new GoodsModel();
                PrepareGoodsPictureModel(model, null);
                PrepareGoodsSpecModel(model, null);
                PrepareGoodsAttrModel(model, null);
                PrepareAttrTableModel(model, null);
                PrepareCategoryMapping(model, null);
                PrepareBrandMapping(model, null);
                PrepareTags(model, goods);
                return View(model);
            }
            else
            {
                var model = goods.ToModel<GoodsModel>();
                PrepareGoodsPictureModel(model, goods);
                PrepareGoodsSpecModel(model, goods);
                PrepareGoodsAttrModel(model, goods);
                PrepareAttrTableModel(model, goods);
                PrepareCategoryMapping(model, goods);
                PrepareBrandMapping(model, goods);
                PrepareTags(model, goods);
                PrepareGoodsModel(model, goods, false);

                return View(model);
            }

        }

        [HttpPost]
        public IActionResult Edit(GoodsModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            var goods = _goodsService.GetGoodsById(model.Id);
            if (goods == null || goods.Deleted)
            {
                if (ModelState.IsValid)
                {
                    goods = model.ToEntity<Goods>();
                    goods.CreateTime = DateTime.Now;
                    goods.UpdateTime = DateTime.Now;
                    _goodsService.InsertGoods(goods);
                    //update pictures
                    if (!string.IsNullOrEmpty(model.imgs))
                    {
                        var ppictures = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PreparePic>>(model.imgs) ?? new List<PreparePic>();
                        SaveGoodsPicture(goods, ppictures.Select(q => q.pictureId).ToArray());
                    }
                    if (!string.IsNullOrEmpty(model.canshu))
                    {
                        var specs = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PrepareSpec>>(model.canshu) ?? new List<PrepareSpec>();
                        SaveGoodsSpec(goods, specs.Select(q => q.valid).ToArray());
                    }
                    if (!string.IsNullOrEmpty(model.attr))
                    {
                        var attrs = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PrepareAttr>>(model.attr) ?? new List<PrepareAttr>();
                        SaveGoodsAttr(goods, attrs);
                    }
                    if (!string.IsNullOrEmpty(model.attrtable))
                    {
                        var attrtables = Newtonsoft.Json.JsonConvert.DeserializeObject<List<AttrTable>>(model.attrtable) ?? new List<AttrTable>();

                        SaveAttrTable(goods, attrtables);
                    }
                    SaveGoodsCategory(goods, model.CategoryIds);
                    //tags (after variant because it can effect goods count)
                    SaveGoodsTags(goods, ParseGoodsTags(model.GoodsTags));
                    //activity log
                    _activityLogService.InsertActivity("AddNewGoods", _localizationService.GetResource("ActivityLog.AddNewGoods"), goods.Name);
                }
            }
            else
            {
                if (ModelState.IsValid)
                {
                    var prevStockQuantity = goods.StockQuantity;
                    //goods
                    goods = model.ToEntity(goods);
                    goods.UpdateTime = DateTime.Now;
                    _goodsService.UpdateGoods(goods);
                    //update pictures
                    if (!string.IsNullOrEmpty(model.imgs))
                    {
                        var ppictures = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PreparePic>>(model.imgs) ?? new List<PreparePic>();
                        SaveGoodsPicture(goods, ppictures.Select(q => q.pictureId).ToArray());
                    }
                    if (!string.IsNullOrEmpty(model.canshu))
                    {
                        var specs = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PrepareSpec>>(model.canshu) ?? new List<PrepareSpec>();
                        SaveGoodsSpec(goods, specs.Select(q => q.valid).ToArray());
                    }
                    if (!string.IsNullOrEmpty(model.attr))
                    {
                        var attrs = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PrepareAttr>>(model.attr) ?? new List<PrepareAttr>();
                        SaveGoodsAttr(goods, attrs);
                    }
                    if (!string.IsNullOrEmpty(model.attrtable))
                    {
                        var attrtables = Newtonsoft.Json.JsonConvert.DeserializeObject<List<AttrTable>>(model.attrtable) ?? new List<AttrTable>();

                        SaveAttrTable(goods, attrtables);
                    }
                    SaveGoodsCategory(goods, model.CategoryIds);
                    //tags
                    SaveGoodsTags(goods, ParseGoodsTags(model.GoodsTags));

                    //activity log
                    _activityLogService.InsertActivity("EditGoods", _localizationService.GetResource("ActivityLog.EditGoods"), goods.Name);
                }
            }

            return Json(new { success = 1, goodsId = goods != null ? goods.Id : 0 });
        }

        public IActionResult Search(int goodsId, string keyword)
        {
            var pc = _categoryService.GetCategoriesByGoodsId(goodsId);

            var categories = _categoryService.GetAllCategories(keyword);

            var result = new ResponseResult
            {
                data = categories.Select(x =>
                {
                    bool select = false; bool disabled = false;
                    if (pc != null && pc.Select(q => q.Id).Contains(x.Id))
                        select = true;

                    if (x.Deleted)
                        disabled = true;

                    var item = new { name = x.GetCategoryBreadCrumb(_categoryService), value = x.Id, selected = select ? "selected" : "", disabled = disabled ? "disabled" : "" };
                    return item;
                }),
                count = categories.Count
            };
            return Json(result);
        }

        //delete goods
        [HttpPost]
        public IActionResult Delete(int id)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            var goods = _goodsService.GetGoodsById(id);
            _goodsService.DeleteGoods(goods);
            //update goods tag totals
            UpdateGoodsTagTotals(goods);

            //activity log
            _activityLogService.InsertActivity("DeleteGoods", _localizationService.GetResource("ActivityLog.DeleteGoods"), goods.Name);

            return Json(new { success = 1 });
        }
        [HttpPost]
        public IActionResult DeleteSelected(ICollection<int> selectedIds)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            var list = new List<Goods>();
            if (selectedIds != null)
            {
                list.AddRange(_goodsService.GetGoodssByIds(selectedIds.ToArray()));

                for (int i = 0; i < list.Count; i++)
                {
                    var goods = list[i];
                    _goodsService.DeleteGoods(goods);
                    //update goods tag totals
                    UpdateGoodsTagTotals(goods);
                }
            }

            return Json(new { success = 1 });
        }

        [HttpPost]
        public IActionResult Published(CheckboxModel checkbox)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog))
                return HttpUnauthorized();

            var goods = _goodsService.GetGoodsById(checkbox.Id);
            if (goods == null)
                return Json(new { error = 1 });

            if (checkbox.Checked)
                goods.Published = true;
            else
                goods.Published = false;
            _goodsService.UpdateGoods(goods);

            return Json(new { success = 1 });
        }

        #endregion

        #region LowStockReport

        public IActionResult LowStockReport()
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            return View();
        }

        [HttpPost]
        public IActionResult LowStockReportList(PageRequest command)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            var list = _goodsService.GetLowStockGoodss(command.Page - 1, command.Limit);

            IList<GoodsSpecCombination> combinations = _goodsService.GetLowStockGoodsCombinations();

            var models = new List<LowStockGoodsModel>();
            foreach (var goods in list)
            {
                var lowStockModel = new LowStockGoodsModel
                {
                    Id = goods.Id,
                    Name = goods.Name,
                    ManageInventoryMethod = goods.ManageStockEnabled,
                    StockQuantity = goods.StockQuantity,
                    Published = goods.Published
                };
                models.Add(lowStockModel);
            }
            //combinations
            foreach (var combination in combinations)
            {
                var goods = _goodsService.GetGoodsById(combination.GoodsId);
                var lowStockModel = new LowStockGoodsModel
                {
                    Id = goods.Id,
                    Name = goods.Name,
                    Attributes = _goodsSpecFormatter.FormatAttributes(combination.AttributesXml, "<br />", true, true, true, false),
                    ManageInventoryMethod = goods.ManageStockEnabled,
                    StockQuantity = combination.StockQuantity,
                    Published = goods.Published
                };
                models.Add(lowStockModel);
            }

            var result = new ResponseResult()
            {
                data = models,
                count = list.Count
            };
            return Json(result);
        }

        #endregion

        #region Goods specification attributes


        public IActionResult GoodsGoodsParameterAdd(int goodsParameterOptionId,
            string customValue, bool allowFiltering, bool showOnGoodsPage,
            int displayOrder, int goodsId)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            var psa = new GoodsParameterMapping()
            {
                GoodsParameterOptionId = goodsParameterOptionId,
                GoodsId = goodsId,
                CustomValue = customValue,
                AllowFiltering = allowFiltering,
                DisplayOrder = displayOrder,
            };
            _goodsParameterService.InsertGoodsParameterMapping(psa);

            return Json(new { Result = true });
        }

        [HttpPost]
        public IActionResult GoodsSpecAttrList(PageRequest command, int goodsId)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            var goodsrSpecs = _goodsParameterService.GetGoodsParameterMappingByGoodsId(goodsId);

            var goodsrSpecsModel = goodsrSpecs
                .Select(x =>
                {
                    var psaModel = new GoodsParameterMappingModel()
                    {
                        Id = x.Id,
                        GoodsParameterName = x.GoodsParameterOption.Mapping.Name,
                        GoodsParameterOptionName = x.GoodsParameterOption.Name,
                        CustomValue = x.CustomValue,
                        AllowFiltering = x.AllowFiltering,
                        DisplayOrder = x.DisplayOrder
                    };
                    return psaModel;
                })
                .ToList();

            var model = new ResponseResult
            {
                data = goodsrSpecsModel,
                count = goodsrSpecsModel.Count
            };

            return Json(model);
        }


        public IActionResult GoodsSpecAttrUpdate(GoodsParameterMappingModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            var psa = _goodsParameterService.GetGoodsParameterMappingById(model.Id);
            psa.CustomValue = model.CustomValue;
            psa.AllowFiltering = model.AllowFiltering;
            psa.DisplayOrder = model.DisplayOrder;
            _goodsParameterService.UpdateGoodsParameterMapping(psa);

            return new NullJsonResult();
        }


        public IActionResult GoodsSpecAttrDelete(int id)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            var psa = _goodsParameterService.GetGoodsParameterMappingById(id);
            if (psa == null)
                throw new ArgumentException("No specification attribute found with the specified id");

            var goodsId = psa.GoodsId;
            _goodsParameterService.DeleteGoodsParameterMapping(psa);

            return new NullJsonResult();
        }

        #endregion

        #region Goods tags

        public IActionResult GoodsTags()
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            return View();
        }

        [HttpPost]
        public IActionResult GoodsTagsJson(PageRequest command)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            var tags = _goodsTagService.GetAllGoodsTags(true)
                .Select(x =>
                {
                    return new GoodsTagModel()
                    {
                        Id = x.Id,
                        Name = x.Name,
                        GoodsCount = x.Count
                    };
                }).ToList();

            var model = new ResponseResult
            {
                data = tags,
                count = tags.Count()
            };
            return Json(model);
        }


        public IActionResult GoodsTagDelete(int id, PageRequest command)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            var tag = _goodsTagService.GetGoodsTagById(id);
            if (tag == null)
                return Json(new { error = 1 });
            _goodsTagService.DeleteGoodsTag(tag);

            return Json(new { success = 1 });
        }

        //edit
        public IActionResult EditGoodsTag(int id)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            var goodsTag = _goodsTagService.GetGoodsTagById(id);
            if (goodsTag == null)
            {
                var model = new GoodsTagModel();
                return View(model);
            }
            else
            {
                var model = new GoodsTagModel()
                {
                    Id = goodsTag.Id,
                    Name = goodsTag.Name,
                    GoodsCount = goodsTag.Count
                };
                return View(model);
            }
        }

        [HttpPost]
        public IActionResult EditGoodsTag(GoodsTagModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            var goodsTag = _goodsTagService.GetGoodsTagById(model.Id);
            if (goodsTag == null)
            {
                goodsTag = new GoodsTag()
                {
                    Name = model.Name
                };
                _goodsTagService.InsertGoodsTag(goodsTag);
                return Json(new { success = 1 });
            }

            if (ModelState.IsValid)
            {
                goodsTag.Name = model.Name;
                _goodsTagService.UpdateGoodsTag(goodsTag);
            }
            //If we got this far, something failed, redisplay form
            return Json(new { success = 1 });
        }

        #endregion

        #region Export / Import

        [HttpPost, ActionName("List")]
        [FormValueRequired("exportexcel-all")]
        public IActionResult ExportExcelAll()
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            try
            {
                var list = _goodsService.SearchGoodss(out IList<int> filterableGoodsParameterOptionIds,
                     orderBy: GoodsSortingEnum.Position, showHidden: true);

                byte[] bytes = null;
                using (var stream = new MemoryStream())
                {
                    _exportManager.ExportGoodssToXlsx(stream, list);
                    bytes = stream.ToArray();
                }
                return File(bytes, "text/xls", "goods.xlsx");
            }
            catch (Exception exc)
            {
                return RedirectToAction("List");
            }
        }

        public IActionResult ExportExcelSelected(string selectedIds)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            var list = new List<Goods>();
            if (selectedIds != null)
            {
                var ids = selectedIds
                    .Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                    .Select(x => Convert.ToInt32(x))
                    .ToArray();
                list.AddRange(_goodsService.GetGoodssByIds(ids));
            }

            byte[] bytes = null;
            using (var stream = new MemoryStream())
            {
                _exportManager.ExportGoodssToXlsx(stream, list);
                bytes = stream.ToArray();
            }
            return File(bytes, "text/xls", "goods.xlsx");
        }

        [HttpPost]
        public IActionResult ImportExcel(IFormFile importexcelfile)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageGoods))
                return HttpUnauthorized();

            try
            {
                if (importexcelfile != null && importexcelfile.Length > 0)
                {
                    _importManager.ImportGoodssFromXlsx(importexcelfile.OpenReadStream());
                }
                else
                {
                    return RedirectToAction("List");
                }
                return RedirectToAction("List");
            }
            catch (Exception exc)
            {
                return RedirectToAction("List");
            }
        }

        #endregion

        #endregion
    }
}
